/**
 * Software License, Version 1.0 Copyright 2003 The Trustees of Indiana
 * University. All rights reserved. Redistribution and use in source and binary
 * forms, with or without modification, are permitted provided that the
 * following conditions are met: 1) All redistributions of source code must
 * retain the above copyright notice, the list of authors in the original source
 * code, this list of conditions and the disclaimer listed in this license; 2)
 * All redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the disclaimer listed in this license in the
 * documentation and/or other materials provided with the distribution; 3) Any
 * documentation included with all redistributions must include the following
 * acknowledgement: "This product includes software developed by the Community
 * Grids Lab. For further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/." Alternatively, this acknowledgement may
 * appear in the software itself, and wherever such third-party acknowledgments
 * normally appear. 4) The name Indiana University or Community Grids Lab or
 * NaradaBrokering, shall not be used to endorse or promote products derived
 * from this software without prior written permission from Indiana University.
 * For written permission, please contact the Advanced Research and Technology
 * Institute ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202. 5)
 * Products derived from this software may not be called NaradaBrokering, nor
 * may Indiana University or Community Grids Lab or NaradaBrokering appear in
 * their name, without prior written permission of ARTI. Indiana University
 * provides no reassurances that the source code provided does not infringe the
 * patent or any other intellectual property rights of any other entity. Indiana
 * University disclaims any liability to any recipient for claims brought by any
 * other entity based on infringement of intellectual property rights or
 * otherwise. LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH
 * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY
 * GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 * INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 * INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 * "VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 * LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 * ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 * GENERATED USING SOFTWARE.
 */
package cgl.narada.test.security;

import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Random;
import java.util.TimeZone;

import org.apache.log4j.Logger;

import cgl.narada.discovery.topics.Entity;
import cgl.narada.discovery.topics.messages.SignedTopicAdvertisement;
import cgl.narada.event.NBEvent;
import cgl.narada.event.TemplateInfo;
import cgl.narada.event.TemplateProfileAndSynopsisTypes;
import cgl.narada.event.impl.TemplateInfoImpl;
import cgl.narada.service.ServiceException;
import cgl.narada.service.client.ClientService;
import cgl.narada.service.client.EventProducer;
import cgl.narada.service.client.SessionService;
import cgl.narada.service.qos.ProducerConstraints;
import cgl.narada.service.security.kmc.KMCClient;
import cgl.narada.service.security.kmc.SignedSecurityToken;
import cgl.narada.service.security.kmc.messages.SecureTopicKeyResponse;
import cgl.narada.service.security.securityprovider.CertificateManager;
import cgl.narada.service.security.securityprovider.CertificateUtil;
import cgl.narada.util.SystemInit;
import cgl.narada.util.SystemNotInitializedException;

/**
 * <br>
 * Created on Sep 9, 2005
 * 
 * @author Harshawardhan Gadgil (hgadgil@grids.ucs.indiana.edu)
 */
public class SecureDataSender {
	static Logger log = Logger.getLogger("SecureDataSender");

	public static void main(String[] args) {
		SystemInit.init();

		if (args.length > 0) host = args[0];
		if (args.length > 1) port = args[1];
		if (args.length > 2) prot = args[2];

		SecureDataSender sender = new SecureDataSender();
	}

	public SecureDataSender() {

		String keystore = null;
		try {
			configFileLocation = SystemInit
					.getInitData(SystemInit.SYS_SERVICE_CONFIG_PATH);
			keystore = SystemInit.getInitData(SystemInit.SYS_KEYSTORE);
		}
		catch (SystemNotInitializedException e) {
			e.printStackTrace();
		}

		initTokens(keystore);
		init();
		System.out.println("---------\nReady to publish...\n------------");
		try {
			System.in.read();
		}
		catch (IOException e) {}

		sendMessage("Secure Message");
		sendMessage("Hello World");
		sendMessage("This is an encrypted and Secure message !");
		sendMessage("This will be auto encrypted using NB Security Framework !");
		sendMessage("Thanks to the developers for all the hard work for making secure messaging possible !");
		sendMessage("Digitally Signed by,");
		sendMessage("Guess WHO ! ;)");
	}

	private static String host = "localhost";
	private static String port = "25000";
	private static String prot = "niotcp";
	private String configFileLocation;
	private String topicName = "encrypted";
	private String topicUUID;
	private PrivateKey c1_priv;

	private EventProducer producer;

	SecureTopicKeyResponse resp;
	ProducerConstraints pc;

	public void sendMessage(String message) {
		try {
			NBEvent nbEvent = producer.generateEvent(
					TemplateProfileAndSynopsisTypes.STRING, topicUUID, message
							.getBytes());
			producer.publishEvent(nbEvent, pc);
		}
		catch (ServiceException e) {
			log.error("", e);
		}
	}

	private void init() {

		// IMP: Might conflict w/ other ppl's entity IDs Maintain constant for
		// now
		int entityId = (new Random()).nextInt();

		Properties prop = new Properties();

		prop.put("hostname", host);
		prop.put("portnum", port);

		log.info("SecureTopicsManager:- TCP @ " + host + ":" + port
				+ " EntityID[" + entityId + "]");

		try {
			ClientService clientService = SessionService.getClientService(
					entityId, configFileLocation);

			clientService.initializeBrokerCommunications(prop, prot);

			producer = clientService.createEventProducer();
			producer.setSuppressRedistributionToSource(true);
			producer.generateEventIdentifier(true);
			producer.setTemplateId(12345);
			producer.setDisableTimestamp(false);

			Properties props = new Properties();
			props.put(ProducerConstraints.SIGNING_ALGORITHM, "SHA1withRSA");
			props.put(ProducerConstraints.CIPHER_MODE, "CBC");
			props.put(ProducerConstraints.CIPHER_PADDING, "PKCS7Padding");

			TemplateInfo ti = new TemplateInfoImpl(12345,
					TemplateProfileAndSynopsisTypes.STRING, topicUUID);

			pc = producer.createProducerConstraints(ti);
			pc.setSendSecurely();
			pc.setSecurityToken(resp.getSignedSecurityToken(), resp.getKey(),
					c1_priv, props);

		}
		catch (ServiceException e) {
			log.error("", e);
		}
	}

	private void initTokens(String keystore) {
		CertificateManager certMan = new CertificateManager();
		certMan.init(keystore, null);

		PublicKey rootCA = CertificateUtil.getPublicKey(certMan,
				certMan.ROOT_CA_ALIAS);

		Certificate c1_cert = CertificateUtil.getCertificate(certMan, "c1");
		c1_priv = CertificateUtil.getPrivateKey(certMan, "c1");

		Calendar until = Calendar.getInstance(TimeZone.getTimeZone("GMT-5"));
		until.add(Calendar.HOUR, 1);

		Entity e = new Entity(9999, configFileLocation, "c1", c1_cert, c1_priv,
				rootCA, host, port, prot);

		if (e == null) {
			System.out.println("ERRRORRRR !!!!");
			return;
		}

		createTopic(e, topicName, TemplateProfileAndSynopsisTypes.STRING, until);

		KMCClient client = new KMCClient(c1_cert, c1_priv, rootCA, "/kmc/c1",
				configFileLocation, host, port, prot);

		// Get Signed Topic Ad
		SignedTopicAdvertisement sta = e.getSignedTopicAdvertisement(topicName);

		topicUUID = sta.getTopicAd().getTopicSynopsis();

		// Set the access control lists
		Hashtable pubs = new Hashtable();
		pubs.put(((X509Certificate) c1_cert).getSubjectDN().getName(), until);

		Hashtable subs = new Hashtable();
		subs.put(((X509Certificate) c1_cert).getSubjectDN().getName(), until);
		subs.put("CN=client2, OU=CGL, O=IU, L=Bloomington, C=US", until);

		// Ok, now register the topic and get a security token
		resp = client.registerTopic(pubs, subs, sta, c1_cert, until, "AES",
				256, 5000);

		// Check the response
		SignedSecurityToken tok = resp.getSignedSecurityToken();
		System.out.println("VERIFICATION: " + tok.verify());
		System.out.println("Publish: "
				+ tok.getSecurityToken().getRights().hasPublishRight());
		System.out.println("Subscribe: "
				+ tok.getSecurityToken().getRights().hasSubscribeRight());
	}

	public boolean createTopic(Entity e, String topicName, int topicType,
			Calendar until) {

		if (e.sendTDNDiscoveryRequest(10000)) {
			System.out.println("Found TDN ! Proceeding to create TOPIC !!");

			if (!e.createTopic("SELF", until, "Test Topic", topicType,
					topicName, null, 5000)) {
				System.err.println("Could not create topic ! Aborting...");
				return false;
			}

			System.out.println("TOPIC Created: UUID -> "
					+ e.getTopicUUID(topicName));
			return true;
		}
		else {
			System.out
					.println("NO TDN found within specified timeout period !!");
			return false;
		}
	}

}
